%% task6_2_1_2.m

clear;
ConstantDefinition()
load("..\data\ConstantDefinition.mat", "sampRate");

dfh_score = [2, 5, 1;
    2, 5, 0.5;
    2, 6, 0.5;
    2, 2, 2;
    2, 1, 1;
    2, 1, 0.5;
    1, 6, 0.5;
    2, 2, 2];

mus = SoundSynthesis6_2_1_2(dfh_score, 120);
sound(mus, sampRate);
% audiowrite("dongfanghong1.wav",mus,sampRate);
plot(mus);

%% ConstantDefinition.m
function ConstantDefinition()
% ConstantDefinition 设置全局常量并保存在ConstantDefinition.mat里，用到时load即可

    % used in function SingleSound
    phi = 0;            % 初始相位
    turnPoint1 = 0.25;   % 转折点
    turnPoint2 = 0.35;
    turnPoint3 = 0.7;
    Arate = 1.5;        % 最大值占平稳时幅值的比率

    % used in function SoundSynthesis
    sampRate = 44100;
    overlapRate = 0.4;

    save("..\data\ConstantDefinition.mat", "phi", "turnPoint1", "turnPoint2", "turnPoint3", "Arate", ...
        "sampRate", "overlapRate");
end

%% SoundSynthesis.m

function res = SoundSynthesis6_2_1_2(musicScore, bpm)
% SoundSynthesis 将SingleSound得到的许多单音按一定的重叠比率整合为一条音频
%   musicScore: 乐谱参数，默认F调，以下方的fre_f为准。
%               size: [n 3] n行，1,2列分别为小字几组和对应唱名，3行为所占拍数
%               （后期可扩展，实现每个音单独设置其相应参数）（ps：什么UTAU）
%   overlapRate: 重叠率，后一个音与前一个音的衰减部分比率
%   bpm: 每分钟拍数，衡量音乐速率
% res: 返回以正弦波为基础的幅值发生衰减的采样后的离散值
%      大小[:,1]

    % F调唱名对应频率
    % 第一行小字组，第二行小字一组
    fre_f = [174.61, 196, 220, 233.08, 261.63, 293.66, 329.63;
             349.23, 392, 440, 466.16, 523.25, 587.33, 659.25];
    dur = 60 / bpm;     % 每拍所占时长（单位：秒）
    load("..\data\ConstantDefinition.mat", "turnPoint3", "sampRate", "overlapRate");
    offset = 0;         % 重叠时向前偏移值
    i = 1;              % 循环变量
    res = 0;
    for index = musicScore'
        sou = SingleSound6_2_1_2(fre_f(index(1),index(2)), sampRate, 10, ...
                (index(3) * dur) / (1-overlapRate+overlapRate*turnPoint3));
        i = i - offset;
        j = 1;
        while i <= size(res,1) && i > 1
            res(i, 1) = res(i) + sou(j);
            j = j + 1;
            i = i + 1;
        end
        while j <= size(sou,1)
            res(i, 1) = sou(j);
            j = j + 1;
            i = i + 1;
        end
        offset = ceil(overlapRate * (1 - turnPoint3) * size(sou, 1));
    end
end

%% SingleSound.m

function res = SingleSound6_2_1_2(fre, sampRate, amplitude, durat)
% SingleSound: 单个乐音生成器
% fre: 乐音频率
% sampRate: 采样率
% amplitude: 乐音幅值（持续时幅值）
% durat: 乐音时长（单位：秒）
% res: 返回以正弦波为基础的幅值发生衰减的采样后的离散值
%      大小[时长*采样率 + 1， 1]

    res = zeros(ceil(durat * sampRate), 1);
    load("..\data\ConstantDefinition.mat", "phi", "turnPoint1", "turnPoint2", "turnPoint3", "Arate");
    ind = 1;            % 循环变量
    for t = 0:1/sampRate:durat
        if t <= turnPoint1 * durat
            res(ind,1) = (Arate * amplitude / turnPoint1 / durat * t) * sin(fre * t + phi);
        elseif t <= turnPoint2 * durat
            res(ind,1) = (-(Arate - 1) * amplitude / (turnPoint2 - turnPoint1) / durat * t + ...
                (Arate * turnPoint2 - turnPoint1) * amplitude / (turnPoint2 - turnPoint1)) * ...
                sin(fre * t + phi);
        elseif t <= turnPoint3 * durat
            res(ind,1) = amplitude * sin(fre * t + phi);
        else
            res(ind,1) = (amplitude / (1 - turnPoint3) / durat * (durat - t)) * ...
                sin(fre * t + phi);
        end
        ind = ind + 1;
    end
end